package ufpi.br.dao;

import java.util.Collection;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;

import br.ufpi.domain.Pergunta;
import br.ufpi.domain.Resposta;
import br.ufpi.domain.Usuario;
import java.util.ArrayList;
import java.util.Date;
import org.hibernate.criterion.Disjunction;
import org.hibernate.criterion.LogicalExpression;
import org.hibernate.criterion.Order;

public class PerguntaDao extends DAOImpl<Pergunta> {

    public PerguntaDao() {
        super(Pergunta.class);
    }

    @Override
    protected Long getIdObj(Pergunta obj) {
        return obj.getId();
    }

    @Override
    protected void setIdObj(Pergunta obj, Long id) {
        obj.setId(id);
    }

    /**
     * Metodo que retorna as perguntas do banco de dados de um usuario
     * @param matricula
     * @param inicioIntervalo
     * @param maxValor
     * @return
     */
    public List<Pergunta> getMinhasPerguntas(String matricula,
            int inicioIntervalo, int maxValor) {
        UsuarioDao usuarioDao = new UsuarioDao();
        Usuario usuario = usuarioDao.buscaMatricula(matricula);
        Criteria criteria = getSession().createCriteria(getPersistentClass());
        criteria.add(Restrictions.eq("usuario", usuario));
        criteria.setMaxResults(maxValor);
        criteria.setFirstResult(inicioIntervalo);
        return criteria.list();
    }

    /**
     * Metodo que retorna  a quantidade total de perguntas no banco de dados
     * @param matricula
     * @return
     */
    public int getTotalPerguntas(String matricula) {
        UsuarioDao usuarioDao = new UsuarioDao();
        Usuario usuario = usuarioDao.buscaMatricula(matricula);
        Criteria criteria = getSession().createCriteria(getPersistentClass());
        criteria.add(Restrictions.eq("usuario", usuario));
        criteria.setProjection(Projections.rowCount());
        return (Integer) criteria.list().get(0);
    }

    /**
     * Metodo que retorna as respostas do banco de dados de um usuario
     * @param idPergunta
     * @return
     */
    public Collection<Resposta> getMinhasResposta(Long idPergunta) {
        Pergunta pergunta = this.findByID(idPergunta);
        return (Collection<Resposta>) pergunta.getRespostas();
    }

    /**
     * Metodo que retorna as perguntas aceitas do banco de dados
     * @return
     */
    public ArrayList<Pergunta> getPerguntasAceitas() {
        //TODO OLhar se as perguntas aceitas estão com o status iguam a 1
        Criteria criteria = getSession().createCriteria(Pergunta.class);
        criteria.add(Restrictions.eq("status", 0));

        return (ArrayList<Pergunta>) criteria.list();
    }
    //TODO Recriar esta classe analizando todos os status

    /**
     * Metodo que retorna as perguntas do banco de dados
     * @param inicioIntervalo
     * @param maximo
     * @param matricula
     * @param isMinhasPerguntas
     * @param respondidas
     * @param frequencia
     * @return
     */
    public Collection<Object> getPerguntas(int inicioIntervalo, int maximo, String matricula, boolean isMinhasPerguntas, String respondidas, String frequencia) {
        Criteria criteria = getSession().createCriteria(getPersistentClass());
        ArrayList<Object> objetos = new ArrayList<Object>();
        Criterion isrespondidas = null;
        Criterion between = null;
        UsuarioDao dao = new UsuarioDao();
        LogicalExpression expression = null;
        Usuario usuario = null;
        ArrayList<Integer> status = new ArrayList<Integer>();
        usuario = dao.buscaMatricula(matricula);
        if (respondidas.equals("T")) {
            //TODO Analisar se os Numeros estao corretos
            //Todas as perguntas
            Integer statusUsuario[] = {0, 5};
            expression = Restrictions.and(Restrictions.eq("usuario", usuario), Restrictions.in("status", statusUsuario));
            //Colocar status das perguntas
            status.add(1);
            status.add(2);
            status.add(3);
            status.add(4);
        } else {
            if (respondidas.equals("R")) {
                //Retorna apenas as perguntas Respondidas
                status.add(3);
            } else {
                if (respondidas.equals("P")) {
                    status.add(0);
                } else {
                    //Retorna as perguntas não respondidas
                    status.add(4);//Parcialmente Respondida
                    status.add(2);//Respondida e não avaliada
                    status.add(1);//Sem Rsposta
                }
            }
            isrespondidas = Restrictions.in("status", status);

        }
        if (isrespondidas == null) {
            expression = Restrictions.or(Restrictions.in("status", status), expression);
        } else {
            expression = Restrictions.or(Restrictions.in("status", status), isrespondidas);
        }

        if (frequencia.equals("T")) {
        } else {
            Date date = new Date();
            Date dateInstance = new Date();
            util.Datas.Datas data = new util.Datas.Datas();
            if (frequencia.equals("H")) {
            } else {
                if ((frequencia.equals("M"))) {

                    date = data.configurarInicioMes(date);
                } else {
                    date = data.configurarInicioSemana(date);
                }

            }
            between = Restrictions.between("dataEnvio", date, dateInstance);
            expression = Restrictions.and(between, expression);
        }
        if (isMinhasPerguntas) {
            expression = Restrictions.and(Restrictions.eq("usuario", usuario), expression);
        }
        criteria.add(expression);
        criteria.addOrder(Order.desc("id"));
        Criteria criteriatotal = getSession().createCriteria(getPersistentClass());
        criteriatotal.add(expression);
        objetos.add((Integer) criteriatotal.setProjection(Projections.rowCount()).uniqueResult());
        criteria.setMaxResults(maximo);
        // criteria.setFirstResult(inicioIntervalo);
        objetos.add(criteria.list());
        return objetos;
    }

    /**
     * Vai listar todoas as perguntas que tenham respostas
     * nao importando o status da resposta
     *
     * @param status
     * @return
     */
    public Collection<Pergunta> listByStatus(int status) {
        Criteria criteria = getSession().createCriteria(Pergunta.class);
        criteria.add(Restrictions.eq("status", status));
        //  Query q = getSession().createQuery("from Pergunta where status = :status");
        //q.setParameter("status", status);
        //return q.list();
        return criteria.list();
    }

    /**
     * Metodo que lista por status e usuario
     * @param matricula
     * @param status
     * @return
     */
    public Collection<Pergunta> listByStatusAndUsuario(String matricula, int status) {
        Criteria criteria = getSession().createCriteria(Pergunta.class);
        UsuarioDao usuarioDao = new UsuarioDao();
        Usuario usuario = usuarioDao.buscaMatricula(matricula);
        criteria.add(Restrictions.and(Restrictions.eq("status", status), Restrictions.eq("usuario", usuario)));
        criteria.addOrder(Order.desc("id"));
        return criteria.list();
    }

    /**
     * Funcao para listar perguntas aceitas respondidas ou nao
     */
    public Collection<Pergunta> listPerguntasAceitas() {
        Criteria criteria = getSession().createCriteria(Pergunta.class);
        Criterion status1 = Restrictions.eq("status", 1);
        Criterion status2 = Restrictions.eq("status", 2);
        Criterion status3 = Restrictions.eq("status", 3);
        Criterion status4 = Restrictions.eq("status", 4);

        Disjunction dis = Restrictions.disjunction();
        dis.add(status1);
        dis.add(status2);
        dis.add(status3);
        dis.add(status4);
        criteria.add(dis);

        return criteria.list();
    }

    /**
     * Funcao para listar perguntas aceitas respondidas apenas
     * Respondida correta
     * Parcialmente correta
     * Nao analisada
     */
    public Collection<Pergunta> listPerguntasRespondidas() {
        Criteria criteria = getSession().createCriteria(Pergunta.class);

        Criterion status2 = Restrictions.eq("status", 2);
        Criterion status3 = Restrictions.eq("status", 3);
        Criterion status4 = Restrictions.eq("status", 4);
        Criterion status5 = Restrictions.eq("status", 5);

        Disjunction dis = Restrictions.disjunction();
        dis.add(status2);
        dis.add(status3);
        dis.add(status4);
        dis.add(status5);
        criteria.add(dis);
        return criteria.list();
    }

    /**
     * Método de busca por assunto
     * @param assunto
     * @param matricula
     * @return
     */
    public Collection buscarPorAssunto(String assunto, String matricula) {
        //Zero o total de perguntas
        //1 as perguntas;
        ArrayList list = new ArrayList();
        assunto = "%" + assunto + "%";
        Integer[] statusUsario = {0, 5};
        Integer[] status = {1, 2, 3, 4};
        UsuarioDao usuarioDao = new UsuarioDao();
        Usuario usuario = usuarioDao.buscaMatricula(matricula);
        Criteria criteria = getSession().createCriteria(Pergunta.class);
        Criteria total = getSession().createCriteria(Pergunta.class);
        LogicalExpression like = Restrictions.or(Restrictions.ilike("titulo", assunto), Restrictions.ilike("mensagem", assunto));
        LogicalExpression expressionStatus = Restrictions.and(like, Restrictions.in("status", status));
        LogicalExpression expressionUsuario = Restrictions.and(Restrictions.eq("usuario", usuario), Restrictions.in("status", statusUsario));
        like = Restrictions.or(expressionStatus, expressionUsuario);
        criteria.add(like);
        total.add(like);
        list.add(total.setProjection(Projections.rowCount()).uniqueResult());
        criteria.addOrder(Order.desc("id"));
        list.add(criteria.list());
        return list;
    }
}
